In today's increasingly competitive market place, quality is of the utmost concern. Users' expectations are high and thus the reliability of hardware and software is especially important. Customers do not tolerate mistakes and the later a defect is discovered, the more costly it can prove to the manufacturer.
Software is undergoing a revolution in terms of complexity and therefore is becoming difficult to maintain. One area of complexity is the maintenance of “concerns”. A concern is defined as a value, a responsibility, an area of interest, a common functionality and the like, for example, logging, quality of service, security, caching and buffering. During the software lifecycle, there is often a need separate concerns in order to improve maintainability, limit the impact of change, facilitate reuse and promote traceabilty.
Object-oriented technology is one methodology that provides a partial solution to the problem, which will be discussed with reference to FIG. 2. A software object, referred to as an object, is an instance of a software class represented as an encapsulated software component comprising data attributes and functionality. The functionality within a software class is defined by software methods that are executed at run-time. Software classes are developed to represent abstract components of an object-oriented software application.
Programs written in the Java (Java is a trademark of Sun Microsystems Inc) programming language are generally run in a virtual machine environment, rather than directly on hardware. Thus a Java program is typically compiled into byte-code form, and then interpreted by the Java virtual machine (JVM) into hardware commands for the platform on which the JVM is executing. An important advantage of this approach is that Java applications can run on a very wide range of platforms, providing of course that a JVM is available for each platform.
A JVM includes components necessary to load Java classes and execute software methods written in the Java programming language. Java classes are written by programmers in the Java programming language using Java instructions. Java instructions are subsequently encoded as platform independent bytecodes by a Java compiler and stored in binary Java class files until they are executed. On execution, the JVM loads a Java class file into memory and executes the software methods it contains. To execute a software method the JVM decodes and executes the bytecode instructions for the software method using a Java interpreter. Decoding a bytecode instruction involves converting the byte code instruction into one or more appropriate machine code instructions for the computer platform. The machine code instructions are subsequently executed by the computer's processor. This model of operation ensures that Java classes are stored in platform independent bytecode format until execution, and these can thus be loaded and executed on many computer platforms given the presence of a JVM capable of interpreting bytecodes.
In an interpretive environment, such as Java, instances of software classes are created during application run-time as objects in an application. In the OO environment, in order to create a new object as an instance of a class, an application needs to obtain a definition of the class. Class definitions are typically stored within a data store in a computer system such as a hard disk drive. The application loads the class definition from the data store using a software routine called a classloader. Each software application has at least one classloader, and different software applications may have different classloaders. The class, once loaded, is also used to access instances of the class originating outside the application, such as objects passed from other applications as parameter objects. The class is uniquely referenced by the application using a combination of a name of the class (e.g. Logging.class) and a reference to a classloader (e.g. myLog.classLoader) which loaded the class. Only a class with the correct unique reference can be used by the application to access a software object instance of that class. A software object is accessible to an application if the application can access data attributes of the software object and invoke software methods of the object.
FIG. 1 shows a computer system (100) that is used in the class loading process. The system (100) includes a central processing unit (CPU) (115) and a data store (120). The data store (120) is a non-volatile data storage medium such as a hard disk drive. An object-oriented class (125) is stored in binary format in data store (120). The class (125) is used to create software objects as instances of class (125) in an object-oriented application (105). The application (105) is an object-oriented application and includes a classloader (110). Alternatively, the classloader can be defined as part of the Java Runtime Environment. The classloader (110) is a software routine executable by the CPU (115). In use, the classloader (110) loads a software class from the data store (120) when the application (105) creates a new software object.
In OO the concept of modularity provides a way of identifying, encapsulating and manipulating concerns in a hierarchical architecture. In FIG. 2, a user manages “n” different class hierarchies ((200, 205 and 210)—only the parent classes, “ComputerSecurity”, “BankAccount” and nth class “ClassName” are shown for simplicity). The dominant concerns in the system, for example computer security and bank accounts are cleanly encapsulated in the class hierarchy.
OO and other methodologies that exist are only advantageous in situations where there is a “clean” separation between concerns. In any non-trivial system there will also remain other concerns that do not fit neatly within the chosen decomposition, and hence their implementation is scattered across classes in the system. This is known as cross-cutting. Crosscutting poses many problems in program design, comprehension and maintenance. For example, in FIG. 2, the implementation of the PIN reset concern is scattered across several classes. It is difficult to modify that concern without incoherency arising. Identifying and modifying the concerns is time-consuming and the chances of causing errors increase.
Aspect-oriented programming (AOP) as described by Gregor Kiczales et al. in “Aspect-Oriented Programming”, ECOOP, June 1997 and in “Aspect-Oriented Programming with AspectJ” by Ivan Kiselev, Sams publishing, 2002 is a technique for improving the separation of concerns in software. The central idea in AOP is that while the hierarchical modularity mechanisms of object-oriented languages are extremely useful, they are inherently unable to modularise all concerns of interest in complex systems. AOP provides a way of modularising “cross-cutting” concerns, that is, concerns that are distributed across modules, code etc. Advantageously, cross-cutting concerns can be designed and programmed in a modular way, and thereby achieve the benefits of modularity. Such well modularised, cross-cutting concerns are called aspects (i.e. the implementation of a concern) and these allow programmers to implement changes to concerns in a modular manner. With reference to FIG. 3, classes 200, 205 and the nth class (210) are shown. With AOP, the cross-cutting concerns (300, 305), namely, the attribute pinCode and the method for resetting the PIN code, can be encapsulated in a single aspect, hence aiding the developer to modify the concern in a modular fashion.
The main concepts associated with AOP will now be described in more detail.
“Join points”—well defined points in the execution of a program. E.g. Field reference, exception handler execution, class initialisation, object initialisation.
“Pointcut”—identifies the join points that are to be involved in an operation.
“Advice”—code which is executed when a pointcut is reached. “Before advice” is executed before a given pointcut, “after advice” is executed after a pointcut and “around advice” is executed instead of join points picked by a pointcut.
“Weaving”—an aspect-oriented implementation technique that inserts advice code into the underlying application to be advised at the points indicated by pointcuts. Weaving is often performed by a compiler.
FIG. 4 shows an example of a program written in Java supplemented by AOP. The program is a calendar application contained in a Java package (i.e. com.ibm.amc.cal). The aspect (i.e. aspect Trace) is a cross-cutting concern that modularizes tracing across all methods. The pointcut (i.e. pointcut all Methods( )) identifies that all methods in the package are to be involved. The before advice shows the code to be executed before the pointcut and the after advice shows the code to be executed after the pointcut. In this example, a build time tool (e.g the ajc compiler in the aspect-oriented programming language, AspectJ) composes the aspect source file(s) (i.e. aspect Trace) with the target Java source files (e.g. programCode.java) to create Java class files (e.g. className.class).
In order to assist developers of computer programs or service personnel to determine the cause of a problem or the reason for unexpected behavior of a computer system, it is known to generate and store diagnostic information for subsequent analysis. The diagnostic functions built into a product are often inadequate for the service personnel to be able to capture accurate information about the problem. Often for example, diagnosis of a problem may require very detailed diagnostics in a particular subsystem and it is not appropriate to have this level of detail permanently built into the product. Furthermore, there is a need for diagnostics to be performed in an unobtrusive manner.